package pers.netty.chat.client;

import lombok.extern.slf4j.Slf4j;
import pers.netty.chat.common.ClientMsgBuilder;
import pers.netty.chat.common.bean.ChatMsg;
import pers.netty.chat.common.bean.User;
import pers.netty.chat.common.bean.msg.ProtoMsg;
import pers.netty.chat.common.codec.ProtobufDecoder;
import pers.netty.chat.common.codec.ProtobufEncoder;
import pers.netty.util;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author 李醴茝
 */
@Slf4j
@Service
public class ChatClient {

    @Value("${server.address}")
    private String host;

    @Value("${server.port}")
    private int port;

    private EventLoopGroup group = new NioEventLoopGroup();

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), new ThreadPoolExecutor.DiscardOldestPolicy());

    @Autowired
    private ChatClientHandler chatClientHandler;

    private Channel channel;
    private User user;

    /**
     * 唯一标记
     */
    private boolean flag = true;


    @PostConstruct
    public void init() {
        user = new User();
        user.setPlatform(0);
        user.setUid("1");
        user.setNickName("maker-1");
        user.setToken("auth token");
        user.setDevId("apple 8 plus");
        user.setSessionId("session-id-1000001");
        run();
    }

    public void run() {
        doConnect(new Bootstrap(), group);
    }

    public void doConnect(Bootstrap bootstrap, EventLoopGroup eventLoopGroup) {
        ChannelFuture f;
        try {
            if (bootstrap != null) {
                bootstrap.group(eventLoopGroup);
                bootstrap.channel(NioSocketChannel.class);
                bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
                bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
                bootstrap.remoteAddress(host, port);

                // 设置通道初始化
                bootstrap.handler(
                        new ChannelInitializer<SocketChannel>() {
                            @Override
                            public void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast(new ProtobufDecoder());
                                ch.pipeline().addLast(new ProtobufEncoder());
                                ch.pipeline().addLast(chatClientHandler);

                            }
                        }
                );

                f = bootstrap.connect().addListener((ChannelFuture futureListener) ->
                {
                    final EventLoop eventLoop = futureListener.channel().eventLoop();
                    if (!futureListener.isSuccess()) {
                        log.info("与服务端断开连接!在10s之后准备尝试重连!");
                        eventLoop.schedule(() -> doConnect(new Bootstrap(), eventLoop), 10, TimeUnit.SECONDS);

                        flag = false;
                    } else {
                        flag = true;
                    }
                    if (flag) {
                        log.info("EchoClient客户端连接成功!");
                        log.info(new Date() + ": 连接成功，启动控制台线程……");
                        channel = futureListener.channel();
                        startConsoleThread();
                    }

                });
                // 阻塞
                f.channel().closeFuture().sync();
            }
        } catch (Exception e) {
            log.info("客户端连接失败!" + e.getMessage());
        }
    }

    private void startConsoleThread() {
        threadPoolExecutor.execute(() ->
        {
            while (!Thread.interrupted()) {
                System.out.println("输入消息发送至服务端: ");
                Scanner sc = new Scanner(System.in);
                String line = sc.nextLine();
                String[] toAndMsg = util.split(line);
                sendChatMsg(toAndMsg[0], toAndMsg[1]);
            }
        });
    }

    public void sendChatMsg(String content, String touid) {
        log.info("发送消息");
        ChatMsg chatMsg = new ChatMsg(user);
        chatMsg.setContent(content);
        chatMsg.setMsgType(ChatMsg.MSGTYPE.TEXT);
        chatMsg.setTo(touid);
        chatMsg.setMsgId(System.currentTimeMillis());

        ProtoMsg.Message message = ClientMsgBuilder.buildChatMsg(chatMsg, user);
        channel.writeAndFlush(message);
    }
}
